package com.baidu.iit.pvm.runtime;

import com.baidu.iit.pvm.PvmEventConstacts;
import com.baidu.iit.pvm.delegate.ActivityBehavior;
import com.baidu.iit.pvm.delegate.ActivityExecution;
import com.baidu.iit.pvm.delegate.CompositeActivityBehavior;
import com.baidu.iit.pvm.process.ActivityImpl;
import com.baidu.iit.pvm.process.ScopeImpl;

import java.util.List;

/**
 * 在节点获取下次路径的时候触发的操作类
 * Created by 卫立 on 2014/4/7.
 *
 * @ThreadSafe
 */
public class AtomicOperationActivityEnd extends AbstractEventAtomicOperation {

    @Override
    protected ScopeImpl getScope(InterpretableExecution execution) {
        return (ScopeImpl) execution.getActivity();
    }

    @Override
    protected String getEventName() {
        return PvmEventConstacts.EVENTNAME_END;
    }

    @Override
    protected void eventNotificationsCompleted(InterpretableExecution execution) {
        ActivityImpl activity = (ActivityImpl) execution.getActivity();
        ActivityImpl parentActivity = activity.getParentActivity();

        if ( (parentActivity!=null)
                &&(!parentActivity.isScope())
                ) {
            execution.setActivity(parentActivity);
            execution.performOperation(ACTIVITY_END);

        } else if (execution.isProcessInstanceType()) {
            execution.performOperation(PROCESS_END);

        } else if (execution.isScope()) {

            ActivityBehavior parentActivityBehavior = (parentActivity!=null ? parentActivity.getActivityBehavior() : null);
            if (parentActivityBehavior instanceof CompositeActivityBehavior) {
                CompositeActivityBehavior compositeActivityBehavior = (CompositeActivityBehavior) parentActivity.getActivityBehavior();

                if(activity.isScope() && activity.getOutgoingTransitions().isEmpty()) {

                    InterpretableExecution parentScopeExecution = (InterpretableExecution) execution.getParent();
                    execution.destroy();
                    execution.remove();
                    parentScopeExecution.setActivity(parentActivity);
                    compositeActivityBehavior.lastExecutionEnded(parentScopeExecution);
                } else {
                    execution.setActivity(parentActivity);
                    compositeActivityBehavior.lastExecutionEnded(execution);
                }
            } else {

                InterpretableExecution parentScopeExecution = (InterpretableExecution) execution.getParent();
                execution.destroy();
                execution.remove();

                if(activity.getParent() == activity.getProcessDefinition()) {
                    parentScopeExecution.setActivity(activity);
                    if(activity.getOutgoingTransitions().isEmpty()) {
                        parentScopeExecution.end();
                    } else {
                        parentScopeExecution.performOperation(PROCESS_END);
                    }
                } else {
                    parentScopeExecution.setActivity(parentActivity);
                    parentScopeExecution.performOperation(ACTIVITY_END);
                }
            }

        } else {
            execution.remove();
            InterpretableExecution concurrentRoot = (InterpretableExecution) execution.getParent();
            if (concurrentRoot.getExecutions().size()==1) {
                InterpretableExecution lastConcurrent = (InterpretableExecution) concurrentRoot.getExecutions().get(0);
                if (!lastConcurrent.isScope()) {
                    concurrentRoot.setActivity((ActivityImpl) lastConcurrent.getActivity());
                    lastConcurrent.setReplacedBy(concurrentRoot);

                    if (lastConcurrent.getExecutions().size() > 0) {
                        concurrentRoot.getExecutions().clear();
                        for (ActivityExecution childExecution : lastConcurrent.getExecutions()) {
                            InterpretableExecution childInterpretableExecution = (InterpretableExecution) childExecution;
                            ((List)concurrentRoot.getExecutions()).add(childExecution); // casting ... damn generics
                            childInterpretableExecution.setParent(concurrentRoot);
                        }
                        lastConcurrent.getExecutions().clear();
                    }

                    concurrentRoot.setVariablesLocal(lastConcurrent.getVariablesLocal());
                    if (!concurrentRoot.isActive() && lastConcurrent.isActive()) {
                        concurrentRoot.setActive(true);
                    }

                    lastConcurrent.remove();
                } else {
                    lastConcurrent.setConcurrent(false);
                }
            }
        }
    }



    protected boolean isExecutionAloneInParent(InterpretableExecution execution) {
        ScopeImpl parentScope = (ScopeImpl) execution.getActivity().getParent();
        for (InterpretableExecution other: (List<InterpretableExecution>) execution.getParent().getExecutions()) {
            if (other!=execution && parentScope.contains((ActivityImpl) other.getActivity())) {
                return false;
            }
        }
        return true;
    }
}
